home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume17 / delete / part02 < prev    next >
Encoding:
Internet Message Format  |  1991-02-25  |  49.3 KB

  1. From: jik@pit-manager.MIT.EDU (Jonathan I. Kamens)
  2. Newsgroups: comp.sources.misc
  3. Subject: v17i024:  delete - MIT Athena delete/undelete programs, Part02/04
  4. Message-ID: <1991Feb25.180718.4331@sparky.IMD.Sterling.COM>
  5. Date: 25 Feb 91 18:07:18 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 88688dcf 2e89e597 83bae5e1 a0bf0fe3
  8.  
  9. Submitted-by: Jonathan I. Kamens <jik@pit-manager.MIT.EDU>
  10. Posting-number: Volume 17, Issue 24
  11. Archive-name: delete/part02
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then unpack
  15. # it by saving it into a file and typing "sh file".  To overwrite existing
  16. # files, type "sh file -c".  You can also feed this as standard input via
  17. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  18. # will see the following message at the end:
  19. #        "End of archive 2 (of 4)."
  20. # Contents:  Makefile expunge.c lsdel.c undelete.c util.c
  21. # Wrapped by jik@pit-manager on Fri Feb 22 08:14:23 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'Makefile'\"
  25. else
  26. echo shar: Extracting \"'Makefile'\" \(5485 characters\)
  27. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  28. X#     Copyright 1988 Massachusetts Institute of Technology.
  29. X#
  30. X#     For copying and distribution information, see the file
  31. X#     "mit-copyright.h".
  32. X#
  33. X#     $Source: /afs/athena.mit.edu/user/j/jik/delete/src/RCS/Makefile,v $
  34. X#     $Author: jik $
  35. X#     $Header: /afs/athena.mit.edu/user/j/jik/delete/src/RCS/Makefile,v 1.28 91/02/22 07:35:51 jik Exp $
  36. X#
  37. X
  38. XDESTDIR=
  39. XTARGETS=     delete undelete expunge purge lsdel
  40. XINSTALLDIR=     /usr/bin
  41. XMANDIR=        /usr/man
  42. XMANSECT=    1
  43. XCC=         cc
  44. XDEPEND=        /usr/bin/X11/makedepend
  45. XCOMPILE_ET=     compile_et
  46. XLINT=         lint
  47. XDEFINES=    
  48. X
  49. X
  50. X# These variables apply only if you want this program to recognize
  51. X# Andrew File System mount points.  If you don't want to support AFS,
  52. X# then they should all be commented out or set to nothing.
  53. X# 
  54. X# AFSINC is the include directory for AFS header files.  
  55. X# AFSLIB is the library directory that contains the AFS libraries.
  56. X# 
  57. X# AFSINC=        
  58. X# AFSLIB=        
  59. X# AFSINCS=    -I$(AFSINC)
  60. X# AFSLDFLAGS=    -L$(AFSLIB) -L$(AFSLIB)/afs
  61. X# AFSLIBS=    -lsys -lrx -llwp $(AFSLIB)/afs/util.a
  62. X# AFSDEFINES=    -DAFS_MOUNTPOINTS
  63. X
  64. X
  65. X# If you install the com_err library and include files in directories
  66. X# that your compiler and linker know how to find, you don't have to
  67. X# set these variables.  Otherwise, you do.
  68. X# 
  69. X# ETINCS is a -I flag pointing to the directory in which the et header
  70. X# files are stored. 
  71. X# ETLDFLAGS is a -L flag pointing to the directory where the et
  72. X# library is stored.
  73. X# 
  74. X# ETINCS=        
  75. X# ETLDFLAGS=    
  76. X
  77. X
  78. X# You probably won't have to edit anything below this line.
  79. X
  80. XETLIBS=        -lcom_err
  81. XINCLUDES=    $(ETINCS) $(AFSINCS)
  82. XLDFLAGS=    $(ETLDFLAGS) $(AFSLDFLAGS) 
  83. XLIBS=         $(ETLIBS) $(AFSLIBS)
  84. XCDEBUGFLAGS=    -O
  85. XCFLAGS=     $(INCLUDES) $(DEFINES) $(AFSDEFINES) $(CDEBUGFLAGS)
  86. XLINTFLAGS=    -u $(INCLUDES) $(DEFINES) $(AFSDEFINES) $(CDEBUGFLAGS)
  87. XLINTLIBS=    
  88. X
  89. XSRCS=         delete.c undelete.c directories.c pattern.c util.c\
  90. X        expunge.c lsdel.c col.c shell_regexp.c\
  91. X        errors.c stack.c
  92. XINCS=         col.h delete.h directories.h expunge.h lsdel.h\
  93. X        mit-copyright.h pattern.h undelete.h util.h\
  94. X        shell_regexp.h errors.h stack.h
  95. XETS=        delete_errs.h delete_errs.c
  96. XETSRCS=        delete_errs.et
  97. X
  98. XMANS=         man1/delete.1 man1/expunge.1 man1/lsdel.1 man1/purge.1\
  99. X        man1/undelete.1
  100. X
  101. XARCHIVE=    README Makefile PATCHLEVEL $(SRCS) $(INCS) $(MANS)\
  102. X        $(ETSRCS)
  103. XARCHIVEDIRS=     man1
  104. X
  105. XDELETEOBJS=     delete.o util.o delete_errs.o errors.o
  106. XUNDELETEOBJS=     undelete.o directories.o util.o pattern.o\
  107. X        shell_regexp.o delete_errs.o errors.o stack.o
  108. XEXPUNGEOBJS=     expunge.o directories.o pattern.o util.o col.o\
  109. X        shell_regexp.o delete_errs.o errors.o stack.o
  110. XLSDELOBJS=     lsdel.o util.o directories.o pattern.o col.o\
  111. X        shell_regexp.o delete_errs.o errors.o stack.o
  112. X
  113. XDELETESRC=     delete.c util.c delete_errs.c errors.c
  114. XUNDELETESRC=     undelete.c directories.c util.c pattern.c\
  115. X        shell_regexp.c delete_errs.c errors.c stack.c
  116. XEXPUNGESRC=     expunge.c directories.c pattern.c util.c col.c\
  117. X        shell_regexp.c delete_errs.c errors.c stack.c
  118. XLSDELSRC=     lsdel.c util.c directories.c pattern.c col.c\
  119. X        shell_regexp.c delete_errs.c errors.c stack.c
  120. X
  121. X.SUFFIXES: .c .h .et
  122. X
  123. X.et.h: $*.et
  124. X    ${COMPILE_ET} $*.et
  125. X.et.c: $*.et
  126. X    ${COMPILE_ET} $*.et
  127. X
  128. Xall: $(TARGETS)
  129. X
  130. Xlint_all: lint_delete lint_undelete lint_expunge lint_lsdel
  131. X
  132. Xinstall:: bin_install man_install
  133. X
  134. X# Errors are ignored on bin_install and man_install because make on
  135. X# some platforms, in combination with the shell, does really stupid
  136. X# things and detects an error where there is none.
  137. X
  138. Xman_install:
  139. X    -for i in $(TARGETS) ; do\
  140. X      install -c man1/$$i.1\
  141. X        $(DESTDIR)$(MANDIR)/man$(MANSECT)/$$i.$(MANSECT);\
  142. X    done
  143. X
  144. Xbin_install: $(TARGETS)
  145. X    -for i in $(TARGETS) ; do\
  146. X          if [ -f $(DESTDIR)$(INSTALLDIR)/$$i ]; then\
  147. X            mv $(DESTDIR)$(INSTALLDIR)/$$i $(DESTDIR)$(INSTALLDIR)/.#$$i ; \
  148. X          fi; \
  149. X      install -c -s $$i $(DESTDIR)$(INSTALLDIR) ; \
  150. X        done
  151. X
  152. Xdelete: $(DELETEOBJS)
  153. X    $(CC) $(LDFLAGS) $(CFLAGS) -o delete $(DELETEOBJS) $(LIBS)
  154. X
  155. Xsaber_delete:
  156. X    #setopt program_name delete
  157. X    #load $(LDFLAGS) $(CFLAGS) $(DELETESRC) $(LIBS)
  158. X
  159. Xlint_delete: $(DELETESRC)
  160. X    $(LINT) $(LINTFLAGS) $(DELETESRC) $(LINTLIBS)
  161. X
  162. Xundelete: $(UNDELETEOBJS)
  163. X    $(CC) $(LDFLAGS) $(CFLAGS) -o undelete $(UNDELETEOBJS) $(LIBS)
  164. X
  165. Xsaber_undelete:
  166. X    #setopt program_name undelete
  167. X    #load $(LDFLAGS) $(CFLAGS) $(UNDELETESRC) $(LIBS)
  168. X
  169. Xlint_undelete: $(UNDELETESRC)
  170. X    $(LINT) $(LINTFLAGS) $(UNDELETESRC) $(LINTLIBS)
  171. X
  172. Xexpunge: $(EXPUNGEOBJS)
  173. X    $(CC) $(LDFLAGS) $(CFLAGS) -o expunge $(EXPUNGEOBJS) $(LIBS)
  174. X
  175. Xsaber_expunge:
  176. X    #setopt program_name expunge
  177. X    #load $(LDFLAGS) $(CFLAGS) $(EXPUNGESRC) $(LIBS)
  178. X
  179. Xlint_expunge: $(EXPUNGESRC)
  180. X    $(LINT) $(LINTFLAGS) $(EXPUNGESRC) $(LINTLIBS)
  181. X
  182. Xpurge: expunge
  183. X    ln -s expunge purge
  184. X
  185. Xlsdel: $(LSDELOBJS)
  186. X    $(CC) $(LDFLAGS) $(CFLAGS) -o lsdel $(LSDELOBJS) $(LIBS)
  187. X
  188. Xlint_lsdel: $(LSDELSRC)
  189. X    $(LINT) $(LINTFLAGS) $(LSDELSRC) $(LINTLIBS)
  190. X
  191. Xsaber_lsdel:
  192. X    #setopt program_name lsdel
  193. X    #load $(LDFLAGS) $(CFLAGS) $(LSDELSRC) $(LIBS)
  194. X
  195. Xtar: $(ARCHIVE)
  196. X    tar cvf - $(ARCHIVE) | compress > delete.tar.Z
  197. X
  198. Xshar: $(ARCHIVE)
  199. X    makekit -oMANIFEST $(ARCHIVEDIRS) $(ARCHIVE)
  200. X
  201. Xpatch: $(ARCHIVE)
  202. X    makepatch $(ARCHIVE)
  203. X    mv patch delete.patch`cat PATCHLEVEL`
  204. X    shar delete.patch`cat PATCHLEVEL` > delete.patch`cat PATCHLEVEL`.shar
  205. X
  206. Xclean::
  207. X    -rm -f *~ *.bak *.o delete undelete lsdel expunge purge\
  208. X        delete_errs.h delete_errs.c
  209. X
  210. Xdepend: $(SRCS) $(INCS) $(ETS)
  211. X    $(DEPEND) -v $(CFLAGS) -s'# DO NOT DELETE' $(SRCS)
  212. X
  213. X$(DELETEOBJS): delete_errs.h
  214. X$(EXPUNGEOBJS): delete_errs.h
  215. X$(UNDELETEOBJS): delete_errs.h
  216. X$(LSDELOBJS): delete_errs.h
  217. X
  218. X# DO NOT DELETE THIS LINE -- makedepend depends on it
  219. END_OF_FILE
  220. if test 5485 -ne `wc -c <'Makefile'`; then
  221.     echo shar: \"'Makefile'\" unpacked with wrong size!
  222. fi
  223. # end of 'Makefile'
  224. fi
  225. if test -f 'expunge.c' -a "${1}" != "-c" ; then 
  226.   echo shar: Will not clobber existing file \"'expunge.c'\"
  227. else
  228. echo shar: Extracting \"'expunge.c'\" \(11287 characters\)
  229. sed "s/^X//" >'expunge.c' <<'END_OF_FILE'
  230. X/*
  231. X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/expunge.c,v $
  232. X * $Author: jik $
  233. X *
  234. X * This program is part of a package including delete, undelete,
  235. X * lsdel, expunge and purge.  The software suite is meant as a
  236. X * replacement for rm which allows for file recovery.
  237. X * 
  238. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  239. X * For copying and distribution information, see the file "mit-copyright.h."
  240. X */
  241. X
  242. X#if (!defined(lint) && !defined(SABER))
  243. X     static char rcsid_expunge_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/expunge.c,v 1.17 91/02/20 17:42:15 jik Exp $";
  244. X#endif
  245. X
  246. X#include <stdio.h>
  247. X#include <sys/types.h>
  248. X#include <sys/time.h>
  249. X#include <sys/dir.h>
  250. X#include <sys/param.h>
  251. X#ifdef SYSV
  252. X#include <string.h>
  253. X#define index strchr
  254. X#define rindex strrchr
  255. X#else
  256. X#include <strings.h>
  257. X#endif /* SYSV */
  258. X#include <com_err.h>
  259. X#include <errno.h>
  260. X#include "col.h"
  261. X#include "util.h"
  262. X#include "directories.h"
  263. X#include "pattern.h"
  264. X#include "expunge.h"
  265. X#include "shell_regexp.h"
  266. X#include "mit-copyright.h"
  267. X#include "delete_errs.h"
  268. X#include "errors.h"
  269. X
  270. Xextern char *realloc();
  271. Xextern time_t current_time;
  272. Xextern int errno;
  273. X
  274. Xchar *whoami;
  275. X
  276. Xtime_t timev;         /* minimum mod time before undeletion */
  277. X
  278. Xint  interactive,    /* query before each expunge */
  279. X     recursive,        /* expunge undeleted directories recursively */
  280. X     noop,        /* print what would be done instead of doing it */
  281. X     verbose,        /* print a line as each file is deleted */
  282. X     force,        /* do not ask for any confirmation */
  283. X     listfiles,        /* list files at toplevel */
  284. X     yield,        /* print yield of expunge at end */
  285. X     f_links,        /* follow symbolic links */
  286. X     f_mounts;        /* follow mount points */
  287. X
  288. Xint bytes_removed = 0;
  289. X
  290. X
  291. X
  292. X
  293. Xmain(argc, argv)
  294. Xint argc;
  295. Xchar *argv[];
  296. X{
  297. X     extern char *optarg;
  298. X     extern int optind;
  299. X     int arg;
  300. X
  301. X     initialize_del_error_table();
  302. X     
  303. X     whoami = lastpart(argv[0]);
  304. X     if (*whoami == 'p') { /* we're doing a purge */
  305. X      if (argc > 1) {
  306. X           set_error(PURGE_TOO_MANY_ARGS);
  307. X           error("");
  308. X           exit(1);
  309. X      }
  310. X      if (purge())
  311. X           error("purge");
  312. X      exit(error_occurred ? 1 : 0);
  313. X     }
  314. X     timev = 0;
  315. X     yield = interactive = recursive = noop = verbose = listfiles = force = 0;
  316. X     while ((arg = getopt(argc, argv, "t:irfnvlysm")) != EOF) {
  317. X      switch (arg) {
  318. X      case 't':
  319. X           timev = atoi(optarg);
  320. X           break;
  321. X      case 'i':
  322. X           interactive++;
  323. X           break;
  324. X      case 'r':
  325. X           recursive++;
  326. X           break;
  327. X      case 'f':
  328. X           force++;
  329. X           break;
  330. X      case 'n':
  331. X           noop++;
  332. X           break;
  333. X      case 'v':
  334. X           verbose++;
  335. X           break;
  336. X      case 'l':
  337. X           listfiles++;
  338. X           break;
  339. X      case 'y':
  340. X           yield++;
  341. X           break;
  342. X      case 's':
  343. X           f_links++;
  344. X           break;
  345. X      case 'm':
  346. X           f_mounts++;
  347. X           break;
  348. X      default:
  349. X           usage();
  350. X           exit(1);
  351. X      }
  352. X     }
  353. X     report_errors = ! force;
  354. X     
  355. X     if (optind == argc) {
  356. X      char *dir;
  357. X      dir = "."; /* current working directory */
  358. X      if (expunge(&dir, 1))
  359. X           error("expunging .");
  360. X     }
  361. X     else if (expunge(&argv[optind], argc - optind))
  362. X      error("expunge");
  363. X
  364. X     exit((error_occurred && (! force)) ? 1 : 0);
  365. X}
  366. X
  367. X
  368. X
  369. X
  370. X
  371. Xpurge()
  372. X{
  373. X     char *home;
  374. X     int retval;
  375. X     
  376. X     home = Malloc((unsigned) MAXPATHLEN);
  377. X     if (! home) {
  378. X      set_error(errno);
  379. X      error("purge");
  380. X      return error_code;
  381. X     }
  382. X     timev = interactive = noop = verbose = force = 0;
  383. X     yield = listfiles = recursive = 1;
  384. X     if (retval = get_home(home)) {
  385. X      error("purge");
  386. X      return retval;
  387. X     }
  388. X
  389. X     printf("Please be patient.... this may take a while.\n\n");
  390. X
  391. X     if (retval = expunge(&home, 1)) {
  392. X      error("expunge");
  393. X      return retval;
  394. X     }
  395. X     return 0;
  396. X}
  397. X
  398. X
  399. X
  400. X
  401. Xusage()
  402. X{
  403. X     fprintf(stderr, "Usage: %s [ options ] [ filename [ ... ]]\n", whoami);
  404. X     fprintf(stderr, "Options are:\n");
  405. X     fprintf(stderr, "     -r     recursive\n");
  406. X     fprintf(stderr, "     -i     interactive\n");
  407. X     fprintf(stderr, "     -f     force\n");
  408. X     fprintf(stderr, "     -t n   n-day-or-older expunge\n");
  409. X     fprintf(stderr, "     -n     noop\n");
  410. X     fprintf(stderr, "     -v     verbose\n");
  411. X     fprintf(stderr, "     -l     list files before expunging\n");
  412. X     fprintf(stderr, "     -s     follow symbolic links to directories\n");
  413. X     fprintf(stderr, "     -m     follow mount points\n");
  414. X     fprintf(stderr, "     -y     print yield of expunge\n");
  415. X     fprintf(stderr, "     --     end options and start filenames\n");
  416. X}
  417. X
  418. X
  419. X
  420. X
  421. X
  422. Xint expunge(files, num)
  423. Xchar **files;
  424. Xint num;
  425. X{
  426. X     char **found_files;
  427. X     int num_found;
  428. X     int status = 0;
  429. X     int total = 0;
  430. X     filerec *current;
  431. X     int retval;
  432. X     
  433. X     if (initialize_tree())
  434. X      exit(1);
  435. X
  436. X     for ( ; num ; num--) {
  437. X      retval = get_the_files(files[num - 1], &num_found, &found_files);
  438. X      if (retval) {
  439. X           error(files[num - 1]);
  440. X           return retval;
  441. X      }
  442. X           
  443. X      if (num_found) {
  444. X           num_found = process_files(found_files, num_found);
  445. X           if (num_found < 0) {
  446. X            error("process_files");
  447. X            return error_code;
  448. X           }
  449. X      }
  450. X      
  451. X      total += num_found;
  452. X      if (! num_found) if (! force) {
  453. X           /*
  454. X        * There are three different situations here.  Eiter we
  455. X        * are dealing with an existing directory with no
  456. X            * deleted files in it, or we are deleting with a
  457. X            * non-existing deleted file with wildcards, or we are
  458. X            * dealing with a non-existing deleted file without
  459. X            * wildcards.  In the former case we print nothing, and
  460. X            * in the latter cases we print either "no match" or
  461. X            * "not found" respectively
  462. X        */
  463. X           if (no_wildcards(files[num - 1])) {
  464. X            if (! directory_exists(files[num - 1])) {
  465. X             set_error(ENOENT);
  466. X             error(files[num - 1]);
  467. X            }
  468. X           }
  469. X           else {
  470. X            set_error(ENOMATCH);
  471. X            error(files[num - 1]);
  472. X           }
  473. X      }
  474. X     }
  475. X     if (total && listfiles) {
  476. X      if (retval = list_files()) {
  477. X           error("list_files");
  478. X           return retval;
  479. X      }
  480. X      if (! force) if (! top_level()) {
  481. X           set_status(EXPUNGE_NOT_EXPUNGED);
  482. X           return error_code;
  483. X      }
  484. X     }
  485. X     current = get_root_tree();
  486. X     if (current) {
  487. X      if (retval = expunge_specified(current)) {
  488. X           error("expunge_specified");
  489. X           status = retval;
  490. X      }
  491. X     }
  492. X     current = get_cwd_tree();
  493. X     if (current) {
  494. X      if (retval = expunge_specified(current)) {
  495. X           error("expunge_specified");
  496. X           status = retval;
  497. X      }
  498. X     }
  499. X     if (yield) {
  500. X      if (noop)
  501. X           printf("Total that would be expunged: %dk\n",
  502. X              size_to_k(bytes_removed));
  503. X      else
  504. X           printf("Total expunged: %dk\n", size_to_k(bytes_removed));
  505. X     }
  506. X     return status;
  507. X}
  508. X
  509. X
  510. X
  511. Xexpunge_specified(leaf)
  512. Xfilerec *leaf;
  513. X{
  514. X     int status = 0;
  515. X     int do_it = 1;
  516. X     int retval;
  517. X     
  518. X     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR)) {
  519. X      char buf[MAXPATHLEN];
  520. X
  521. X      if (retval = get_leaf_path(leaf, buf)) {
  522. X           error("get_leaf_path");
  523. X           return retval;
  524. X      }
  525. X      (void) convert_to_user_name(buf, buf);
  526. X
  527. X      if (interactive) {
  528. X           printf("%s: Expunge directory %s? ", whoami, buf);
  529. X           status = (! (do_it = yes()));
  530. X      }
  531. X     }
  532. X     if (do_it) {
  533. X      if (leaf->dirs) {
  534. X           if (retval = expunge_specified(leaf->dirs)) {
  535. X            error("expunge_specified");
  536. X            status = retval;
  537. X           }
  538. X      }
  539. X      if (leaf->files) {
  540. X           if (retval = expunge_specified(leaf->files)) {
  541. X            error("expunge_specified");
  542. X            status = retval;
  543. X           }
  544. X      }
  545. X     }
  546. X     if (leaf->specified && (! status)) {
  547. X      if (retval = really_do_expunge(leaf)) {
  548. X           error("really_do_expunge");
  549. X           status = retval;
  550. X      }
  551. X     }
  552. X     if (leaf->next) {
  553. X      if (retval = expunge_specified(leaf->next)) {
  554. X           error("expunge_specified");
  555. X           status = retval;
  556. X      }
  557. X     }
  558. X
  559. X     free_leaf(leaf);
  560. X     return status;
  561. X}
  562. X
  563. X
  564. Xprocess_files(files, num)
  565. Xchar **files;
  566. Xint num;
  567. X{
  568. X     int i, skipped = 0;
  569. X     filerec *leaf;
  570. X     
  571. X     for (i = 0; i < num; i++) {
  572. X      if (add_path_to_tree(files[i], &leaf)) {
  573. X           error("add_path_to_tree");
  574. X           return -1;
  575. X      }
  576. X      free(files[i]);
  577. X      if (! timed_out(leaf, current_time, timev)) {
  578. X           free_leaf(leaf);
  579. X           skipped++;
  580. X      }
  581. X     }
  582. X     free((char *) files);
  583. X     return(num-skipped);
  584. X}
  585. X
  586. X
  587. X
  588. X
  589. X
  590. X
  591. X
  592. X
  593. X
  594. Xreally_do_expunge(file_ent)
  595. Xfilerec *file_ent;
  596. X{
  597. X     char real[MAXPATHLEN], user[MAXPATHLEN];
  598. X     int status;
  599. X     int retval;
  600. X     
  601. X     if (retval = get_leaf_path(file_ent, real)) {
  602. X      error("get_leaf_path");
  603. X      return retval;
  604. X     }
  605. X     (void) convert_to_user_name(real, user);
  606. X
  607. X     if (interactive) {
  608. X      printf ("%s: Expunge %s (%dk)? ", whoami, user,
  609. X          size_to_k(file_ent->specs.st_size));
  610. X      if (! yes()) {
  611. X           set_status(EXPUNGE_NOT_EXPUNGED);
  612. X           return error_code;
  613. X      }
  614. X     }
  615. X
  616. X     if (noop) {
  617. X      bytes_removed += file_ent->specs.st_size;
  618. X      printf("%s: %s (%dk) would be expunged (%dk total)\n", whoami, user,
  619. X         size_to_k(file_ent->specs.st_size),
  620. X         size_to_k(bytes_removed));
  621. X      return 0;
  622. X     }
  623. X
  624. X     if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
  625. X      status = rmdir(real);
  626. X     else
  627. X      status = unlink(real);
  628. X     if (! status) {
  629. X      bytes_removed += file_ent->specs.st_size;
  630. X      if (verbose)
  631. X           printf("%s: %s (%dk) expunged (%dk total)\n", whoami, user,
  632. X              size_to_k(file_ent->specs.st_size),
  633. X              size_to_k(bytes_removed));
  634. X      return 0;
  635. X     }
  636. X     else {
  637. X      set_error(errno);
  638. X      error(real);
  639. X      return error_code;
  640. X     }
  641. X}
  642. X
  643. X
  644. X
  645. X
  646. X
  647. X
  648. X
  649. X
  650. X
  651. Xtop_level()
  652. X{
  653. X     if (interactive) {
  654. Xprintf("The above files, which have been marked for deletion, are about to be\n");
  655. Xprintf("expunged forever!  You will be asked for confirmation before each file is\n");
  656. Xprintf("deleted.  Do you wish to continue [return = no]? ");
  657. X     }
  658. X     else {
  659. Xprintf("The above files, which have been marked for deletion, are about to be\n");
  660. Xprintf("expunged forever!  Make sure you don't need any of them before continuing.\n");
  661. Xprintf("Do you wish to continue [return = no]? ");
  662. X     }
  663. X     return (yes());
  664. X}
  665. X
  666. X
  667. X
  668. X
  669. X
  670. Xlist_files()
  671. X{
  672. X     filerec *current;
  673. X     char **strings;
  674. X     int num;
  675. X     int retval;
  676. X     
  677. X     strings = (char **) Malloc(sizeof(char *));
  678. X     num = 0;
  679. X     if (! strings) {
  680. X      set_error(errno);
  681. X      error("Malloc");
  682. X      return error_code;
  683. X     }
  684. X
  685. X     printf("The following deleted files are going to be expunged: \n\n");
  686. X
  687. X     current = get_root_tree();
  688. X     if (retval = accumulate_names(current, &strings, &num)) {
  689. X      error("accumulate_names");
  690. X      return retval;
  691. X     }
  692. X     current = get_cwd_tree();
  693. X     if (retval = accumulate_names(current, &strings, &num)) {
  694. X      error("accumulate_names");
  695. X      return retval;
  696. X     }
  697. X     if (retval = column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0,
  698. X                   1, stdout)) {
  699. X      error("column_array");
  700. X      return retval;
  701. X     }
  702. X     
  703. X     printf("\n");
  704. X     return(0);
  705. X}
  706. X     
  707. X
  708. X
  709. X
  710. X
  711. Xint get_the_files(name, num_found, found)
  712. Xchar *name;
  713. Xint *num_found;
  714. Xchar ***found;
  715. X{
  716. X     int retval;
  717. X     int options;
  718. X     
  719. X     options = FIND_DELETED | FIND_CONTENTS | RECURS_DELETED;
  720. X     if (recursive)
  721. X      options |= RECURS_FIND_DELETED;
  722. X     if (f_mounts)
  723. X      options |= FOLLW_MOUNTPOINTS;
  724. X     if (f_links)
  725. X      options |= FOLLW_LINKS;
  726. X     
  727. X     retval = find_matches(name, num_found, found, options);
  728. X     if (retval) {
  729. X      error("find_matches");
  730. X      return retval;
  731. X     }
  732. X
  733. X     return 0;
  734. X}
  735. END_OF_FILE
  736. if test 11287 -ne `wc -c <'expunge.c'`; then
  737.     echo shar: \"'expunge.c'\" unpacked with wrong size!
  738. fi
  739. # end of 'expunge.c'
  740. fi
  741. if test -f 'lsdel.c' -a "${1}" != "-c" ; then 
  742.   echo shar: Will not clobber existing file \"'lsdel.c'\"
  743. else
  744. echo shar: Extracting \"'lsdel.c'\" \(7464 characters\)
  745. sed "s/^X//" >'lsdel.c' <<'END_OF_FILE'
  746. X/*
  747. X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/lsdel.c,v $
  748. X * $Author: jik $
  749. X *
  750. X * This program is a replacement for rm.  Instead of actually deleting
  751. X * files, it marks them for deletion by prefixing them with a ".#"
  752. X * prefix.
  753. X *
  754. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  755. X * For copying and distribution information, see the file "mit-copyright.h."
  756. X */
  757. X
  758. X#if (!defined(lint) && !defined(SABER))
  759. X     static char rcsid_lsdel_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/lsdel.c,v 1.14 91/02/20 17:36:11 jik Exp $";
  760. X#endif
  761. X
  762. X#include <stdio.h>
  763. X#include <sys/types.h>
  764. X#include <sys/dir.h>
  765. X#include <sys/param.h>
  766. X#ifdef SYSV
  767. X#include <string.h>
  768. X#define index strchr
  769. X#define rindex strrchr
  770. X#else
  771. X#include <strings.h>
  772. X#endif /* SYSV */
  773. X#ifdef _AUX_SOURCE
  774. Xextern char *strcmp();
  775. X#endif
  776. X#include <errno.h>
  777. X#include <com_err.h>
  778. X#include "col.h"
  779. X#include "util.h"
  780. X#include "directories.h"
  781. X#include "pattern.h"
  782. X#include "lsdel.h"
  783. X#include "shell_regexp.h"
  784. X#include "mit-copyright.h"
  785. X#include "delete_errs.h"
  786. X#include "errors.h"
  787. X
  788. Xextern char *realloc();
  789. Xextern time_t current_time;
  790. Xextern int errno;
  791. X
  792. Xint byte_total = 0;
  793. Xint dirsonly, recursive, yield, f_links, f_mounts;
  794. Xtime_t timev;
  795. X
  796. Xmain(argc, argv)
  797. Xint argc;
  798. Xchar *argv[];
  799. X{
  800. X     extern char *optarg;
  801. X     extern int optind;
  802. X     int arg;
  803. X     
  804. X     whoami = lastpart(argv[0]);
  805. X
  806. X     dirsonly = recursive = timev = yield = f_links = f_mounts = 0;
  807. X     while ((arg = getopt(argc, argv, "drt:ysm")) != -1) {
  808. X      switch (arg) {
  809. X      case 'd':
  810. X           dirsonly++;
  811. X           break;
  812. X      case 'r':
  813. X           recursive++;
  814. X           break;
  815. X      case 't':
  816. X           timev = atoi(optarg);
  817. X           break;
  818. X      case 'y':
  819. X           yield++;
  820. X           break;
  821. X      case 's':
  822. X           f_links++;
  823. X           break;
  824. X      case 'm':
  825. X           f_mounts++;
  826. X           break;
  827. X      default:
  828. X           usage();
  829. X           exit(1);
  830. X      }
  831. X     }
  832. X     if (optind == argc) {
  833. X      char *cwd;
  834. X
  835. X      cwd = ".";
  836. X
  837. X      if (ls(&cwd, 1))
  838. X           error("ls of .");
  839. X     }
  840. X     else if (ls(&argv[optind], argc - optind))
  841. X      error ("ls");
  842. X
  843. X     exit (error_occurred ? 1 : 0);
  844. X}
  845. X
  846. X
  847. X
  848. X
  849. X
  850. X
  851. Xusage()
  852. X{
  853. X     fprintf(stderr, "Usage: %s [ options ] [ filename [ ...]]\n", whoami);
  854. X     fprintf(stderr, "Options are:\n");
  855. X     fprintf(stderr, "     -d     list directory names, not contents\n");
  856. X     fprintf(stderr, "     -r     recursive\n");
  857. X     fprintf(stderr, "     -t n   list n-day-or-older files only\n");
  858. X     fprintf(stderr, "     -y     report total space taken up by files\n");
  859. X     fprintf(stderr, "     -s     follow symbolic links to directories\n");
  860. X     fprintf(stderr, "     -m     follow mount points\n");
  861. X}
  862. X
  863. X
  864. X
  865. X
  866. Xls(args, num)
  867. Xchar **args;
  868. Xint num;
  869. X{
  870. X     char **found_files;
  871. X     int num_found = 0, total = 0;
  872. X     int status = 0;
  873. X     int retval;
  874. X
  875. X     initialize_del_error_table();
  876. X     
  877. X     if (retval = initialize_tree()) {
  878. X      error("initialize_tree");
  879. X      return retval;
  880. X     }
  881. X     
  882. X     for ( ; num; num--) {
  883. X      if (retval = get_the_files(args[num - 1], &num_found,
  884. X                     &found_files)) {
  885. X           error(args[num - 1]);
  886. X           status = retval;
  887. X           continue;
  888. X      }
  889. X
  890. X      if (num_found) {
  891. X           num_found = process_files(found_files, num_found);
  892. X           if (num_found < 0) {
  893. X            error("process_files");
  894. X            status = error_code;
  895. X            continue;
  896. X           }
  897. X           total += num_found;
  898. X      }
  899. X      else {
  900. X           /* What we do at this point depends on exactly what the
  901. X            * filename is.  There are several possible conditions:
  902. X        * 1. The filename has no wildcards in it, which means that
  903. X        *    if we couldn't find it, that means it doesn't
  904. X        *    exist.  Print a not found error.
  905. X        * 2. Filename is an existing directory, with no deleted
  906. X        *    files in it.  Print nothing.
  907. X        * 3. Filename doesn't exist, and there are wildcards in
  908. X        *    it.  Print "no match".
  909. X        * None of these are considered error conditions, so we
  910. X        * don't set the error flag.
  911. X        */
  912. X           if (no_wildcards(args[num - 1])) {
  913. X            if (! directory_exists(args[num - 1])) {
  914. X             set_error(ENOENT);
  915. X             error(args[num - 1]);
  916. X             status = error_code;
  917. X             continue;
  918. X            }
  919. X           }
  920. X           else {
  921. X            set_error(ENOMATCH);
  922. X            error(args[num - 1]);
  923. X            status = error_code;
  924. X            continue;
  925. X           }
  926. X      }
  927. X     }
  928. X     if (total) {
  929. X      if (list_files()) {
  930. X           error("list_files");
  931. X           return error_code;
  932. X      }
  933. X     }
  934. X     if (yield)
  935. X      printf("\nTotal space taken up by file%s: %dk\n",
  936. X         (total == 1 ? "" : "s"), size_to_k(byte_total));
  937. X
  938. X     return status;
  939. X}
  940. X
  941. X
  942. X
  943. X
  944. Xint get_the_files(name, number_found, found)
  945. Xchar *name;
  946. Xint *number_found;
  947. Xchar ***found;
  948. X{
  949. X     int retval;
  950. X     int options;
  951. X     
  952. X     options = FIND_DELETED | FIND_CONTENTS;
  953. X     if (recursive)
  954. X      options |= RECURS_FIND_DELETED;
  955. X     if (! dirsonly)
  956. X      options |= RECURS_DELETED;
  957. X     if (f_mounts)
  958. X      options |= FOLLW_MOUNTPOINTS;
  959. X     if (f_links)
  960. X      options |= FOLLW_LINKS;
  961. X     
  962. X     retval = find_matches(name, number_found, found, options);
  963. X     if (retval) {
  964. X      error("find_matches");
  965. X      return retval;
  966. X     }
  967. X
  968. X     return 0;
  969. X}
  970. X
  971. X
  972. X
  973. X
  974. X
  975. X
  976. Xprocess_files(files, num)
  977. Xchar **files;
  978. Xint num;
  979. X{
  980. X     int i, skipped = 0;
  981. X     filerec *leaf;
  982. X     
  983. X     for (i = 0; i < num; i++) {
  984. X      if (add_path_to_tree(files[i], &leaf)) {
  985. X           error("add_path_to_tree");
  986. X           return -1;
  987. X      }
  988. X      free(files[i]);
  989. X      if (! timed_out(leaf, current_time, timev)) {
  990. X           free_leaf(leaf);
  991. X           skipped++;
  992. X           continue;
  993. X      }
  994. X      byte_total += leaf->specs.st_size;
  995. X     }
  996. X     free((char *) files);
  997. X     return(num-skipped);
  998. X}
  999. X
  1000. X
  1001. X
  1002. X
  1003. X
  1004. Xlist_files()
  1005. X{
  1006. X     filerec *current;
  1007. X     char **strings;
  1008. X     int num;
  1009. X     int retval;
  1010. X     
  1011. X     strings = (char **) Malloc((unsigned) sizeof(char *));
  1012. X     num = 0;
  1013. X     if (! strings) {
  1014. X      set_error(errno);
  1015. X      error("Malloc");
  1016. X      return error_code;
  1017. X     }
  1018. X     current = get_root_tree();
  1019. X     if (retval = accumulate_names(current, &strings, &num)) {
  1020. X      error("accumulate_names");
  1021. X      return retval;
  1022. X     }
  1023. X     current = get_cwd_tree();
  1024. X     if (retval = accumulate_names(current, &strings, &num)) {
  1025. X      error("accumulate_names");
  1026. X      return retval;
  1027. X     }
  1028. X
  1029. X     if (retval = sort_files(strings, num)) {
  1030. X      error("sort_files");
  1031. X      return retval;
  1032. X     }
  1033. X     
  1034. X     if (retval = unique(&strings, &num)) {
  1035. X      error("unique");
  1036. X      return retval;
  1037. X     }
  1038. X     
  1039. X     if (retval = column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0,
  1040. X                   1, stdout)) {
  1041. X      error("column_array");
  1042. X      return retval;
  1043. X     }
  1044. X     
  1045. X     for ( ; num; num--)
  1046. X      free(strings[num - 1]);
  1047. X     free((char *) strings);
  1048. X     return 0;
  1049. X}
  1050. X
  1051. X
  1052. Xint sort_files(data, num_data)
  1053. Xchar **data;
  1054. Xint num_data;
  1055. X{
  1056. X     qsort((char *) data, num_data, sizeof(char *), strcmp);
  1057. X
  1058. X     return 0;
  1059. X}
  1060. X
  1061. X
  1062. Xint unique(the_files, number)
  1063. Xchar ***the_files;
  1064. Xint *number;
  1065. X{
  1066. X     int i, last;
  1067. X     int offset;
  1068. X     char **files;
  1069. X
  1070. X     files = *the_files;
  1071. X     for (last = 0, i = 1; i < *number; i++) {
  1072. X      if (! strcmp(files[last], files[i])) {
  1073. X           free (files[i]);
  1074. X           free (files[i]);
  1075. X           files[i] = (char *) NULL;
  1076. X      }
  1077. X      else
  1078. X           last = i;
  1079. X     }
  1080. X     
  1081. X     for (offset = 0, i = 0; i + offset < *number; i++) {
  1082. X      if (! files[i])
  1083. X           offset++;
  1084. X      if (i + offset < *number)
  1085. X           files[i] = files[i + offset];
  1086. X     }
  1087. X     *number -= offset;
  1088. X     files = (char **) realloc((char *) files,
  1089. X                   (unsigned) (sizeof(char *) * *number));
  1090. X     if ((*number != 0) && (! files)) {
  1091. X      set_error(errno);
  1092. X      error("realloc");
  1093. X      return errno;
  1094. X     }
  1095. X
  1096. X     *the_files = files;
  1097. X     return 0;
  1098. X}
  1099. END_OF_FILE
  1100. if test 7464 -ne `wc -c <'lsdel.c'`; then
  1101.     echo shar: \"'lsdel.c'\" unpacked with wrong size!
  1102. fi
  1103. # end of 'lsdel.c'
  1104. fi
  1105. if test -f 'undelete.c' -a "${1}" != "-c" ; then 
  1106.   echo shar: Will not clobber existing file \"'undelete.c'\"
  1107. else
  1108. echo shar: Extracting \"'undelete.c'\" \(12715 characters\)
  1109. sed "s/^X//" >'undelete.c' <<'END_OF_FILE'
  1110. X/*
  1111. X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/undelete.c,v $
  1112. X * $Author: jik $
  1113. X *
  1114. X * This program is part of a package including delete, undelete,
  1115. X * lsdel, expunge and purge.  The software suite is meant as a
  1116. X * replacement for rm which allows for file recovery.
  1117. X * 
  1118. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  1119. X * For copying and distribution information, see the file "mit-copyright.h."
  1120. X */
  1121. X
  1122. X#if (!defined(lint) && !defined(SABER))
  1123. X     static char rcsid_undelete_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/undelete.c,v 1.22 91/02/20 17:27:38 jik Exp $";
  1124. X#endif
  1125. X
  1126. X#include <stdio.h>
  1127. X#include <sys/types.h>
  1128. X#include <sys/dir.h>
  1129. X#include <sys/param.h>
  1130. X#ifdef SYSV
  1131. X#include <string.h>
  1132. X#define index strchr
  1133. X#define rindex strrchr
  1134. X#else
  1135. X#include <strings.h>
  1136. X#endif /* SYSV */
  1137. X#include <com_err.h>
  1138. X#include <errno.h>
  1139. X#include "delete_errs.h"
  1140. X#include "pattern.h"
  1141. X#include "util.h"
  1142. X#include "directories.h"
  1143. X#include "undelete.h"
  1144. X#include "shell_regexp.h"
  1145. X#include "mit-copyright.h"
  1146. X#include "errors.h"
  1147. X
  1148. Xextern char *realloc();
  1149. Xextern int errno;
  1150. X
  1151. Xint interactive, recursive, verbose, directoriesonly, noop, force;
  1152. X
  1153. X
  1154. Xmain(argc, argv)
  1155. Xint argc;
  1156. Xchar *argv[];
  1157. X{
  1158. X     extern char *optarg;
  1159. X     extern int optind;
  1160. X     int arg;
  1161. X     int retval;
  1162. X     
  1163. X     initialize_del_error_table();
  1164. X     
  1165. X     whoami = lastpart(argv[0]);
  1166. X     interactive = recursive = verbose = directoriesonly = noop = force = 0;
  1167. X
  1168. X     while ((arg = getopt(argc, argv, "firvnR")) != -1) {
  1169. X      switch (arg) {
  1170. X      case 'f':
  1171. X           force++;
  1172. X           break;
  1173. X      case 'i':
  1174. X           interactive++;
  1175. X           break;
  1176. X      case 'r':
  1177. X           recursive++;
  1178. X           if (directoriesonly) {
  1179. X            fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
  1180. X                whoami);
  1181. X            usage();
  1182. X            exit(1);
  1183. X           }
  1184. X           break;
  1185. X      case 'v':
  1186. X           verbose++;
  1187. X           break;
  1188. X      case 'n':
  1189. X           noop++;
  1190. X           break;
  1191. X      case 'R':
  1192. X           directoriesonly++;
  1193. X           if (recursive) {
  1194. X            fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
  1195. X                whoami);
  1196. X            usage();
  1197. X            exit(1);
  1198. X           }
  1199. X           break;
  1200. X      default:
  1201. X           usage();
  1202. X           exit(1);
  1203. X      }
  1204. X     }
  1205. X
  1206. X     report_errors = ! force;
  1207. X     
  1208. X     if (optind == argc) {
  1209. X      if (interactive_mode())
  1210. X           error("interactive_mode");
  1211. X     }
  1212. X     else while (optind < argc) {
  1213. X      retval = undelete(argv[optind]);
  1214. X      if (retval)
  1215. X           error(argv[optind]);
  1216. X      optind++;
  1217. X     }
  1218. X     exit(((! force) && error_occurred) ? 1 : 0);
  1219. X}
  1220. X
  1221. X
  1222. X
  1223. Xinteractive_mode()
  1224. X{
  1225. X     char buf[MAXPATHLEN];
  1226. X     char *ptr;
  1227. X     int status = 0;
  1228. X     int retval;
  1229. X     
  1230. X     if (verbose) {
  1231. X      printf("Enter the files to be undeleted, one file per line.\n");
  1232. X      printf("Hit <RETURN> on a line by itself to exit.\n\n");
  1233. X     }
  1234. X     do {
  1235. X      printf("%s: ", whoami);
  1236. X      ptr = fgets(buf, MAXPATHLEN, stdin);
  1237. X      if (! ptr) {
  1238. X           printf("\n");
  1239. X           return status;
  1240. X      }
  1241. X      ptr = index(buf, '\n');  /* fgets breakage */
  1242. X      if (ptr)
  1243. X           *ptr = '\0';
  1244. X      if (! *buf)
  1245. X           return status;
  1246. X      retval = undelete(buf);
  1247. X      if (retval) {
  1248. X           error(buf);
  1249. X           status = retval;
  1250. X      }
  1251. X     } while (*buf);
  1252. X     return status;
  1253. X}
  1254. X
  1255. X
  1256. X
  1257. Xusage()
  1258. X{
  1259. X     fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
  1260. X     fprintf(stderr, "Options are:\n");
  1261. X     fprintf(stderr, "     -r     recursive\n");
  1262. X     fprintf(stderr, "     -i     interactive\n");
  1263. X     fprintf(stderr, "     -f     force\n");
  1264. X     fprintf(stderr, "     -v     verbose\n");
  1265. X     fprintf(stderr, "     -n     noop\n");
  1266. X     fprintf(stderr, "     -R     directories only (i.e. no recursion)\n");
  1267. X     fprintf(stderr, "     --     end options and start filenames\n");
  1268. X     fprintf(stderr, "-r and -D are mutually exclusive\n");
  1269. X}
  1270. X
  1271. Xundelete(name)
  1272. Xchar *name;
  1273. X{
  1274. X     char **found_files;
  1275. X     int num_found;
  1276. X     int status = 0;
  1277. X     filerec *current;
  1278. X     int retval;
  1279. X     
  1280. X     if (retval =  get_the_files(name, &num_found, &found_files)) {
  1281. X      error(name);
  1282. X      return retval;
  1283. X     }
  1284. X     
  1285. X     if (num_found) {
  1286. X      if (retval = process_files(found_files, num_found)) {
  1287. X           error(name);
  1288. X           return retval;
  1289. X      }
  1290. X      if (*name == '/')
  1291. X           current = get_root_tree();
  1292. X      else
  1293. X           current = get_cwd_tree();
  1294. X
  1295. X      status = recurs_and_undelete(current);
  1296. X      if (status) {
  1297. X           error(name);
  1298. X           return status;
  1299. X      }
  1300. X     }
  1301. X     else {
  1302. X      if (no_wildcards(name)) {
  1303. X           set_error(ENOENT)
  1304. X      }
  1305. X      else
  1306. X           set_error(ENOMATCH);
  1307. X      error(name);
  1308. X      return error_code;
  1309. X     }
  1310. X
  1311. X     return status;
  1312. X}
  1313. X
  1314. X
  1315. X
  1316. X
  1317. X
  1318. Xint recurs_and_undelete(leaf)
  1319. Xfilerec *leaf;
  1320. X{
  1321. X     int status = 0;
  1322. X     int retval;
  1323. X     
  1324. X     if (leaf->specified) {
  1325. X      retval = do_undelete(leaf);
  1326. X      if (retval) {
  1327. X           error("do_undelete");
  1328. X           status = retval;
  1329. X      }
  1330. X     }
  1331. X
  1332. X     if (! status) { /* recurse only if if top-level undelete */
  1333. X             /* succeeded or was not requested        */
  1334. X      if (leaf->dirs) {
  1335. X           retval = recurs_and_undelete(leaf->dirs);
  1336. X           if (retval) {
  1337. X            error("recurs_and_undelete");
  1338. X            status = retval;
  1339. X           }
  1340. X      }
  1341. X
  1342. X      if (leaf->files) {
  1343. X           retval = recurs_and_undelete(leaf->files);
  1344. X           if (retval) {
  1345. X            error("recurs_and_undelete");
  1346. X            status = retval;
  1347. X           }
  1348. X      }
  1349. X     }
  1350. X
  1351. X     if (leaf->next) {
  1352. X      retval = recurs_and_undelete(leaf->next);
  1353. X      if (retval) {
  1354. X           error("recurs_and_undelete");
  1355. X           status = retval;
  1356. X      }
  1357. X     }
  1358. X
  1359. X     free_leaf(leaf);
  1360. X
  1361. X     return status;
  1362. X}
  1363. X
  1364. X
  1365. X
  1366. X
  1367. X
  1368. X
  1369. Xint process_files(files, num)
  1370. Xchar **files;
  1371. Xint num;
  1372. X{
  1373. X     int i;
  1374. X     listrec *filelist;
  1375. X     struct filrec *not_needed;
  1376. X     int retval;
  1377. X     
  1378. X     filelist = (listrec *) Malloc((unsigned) (sizeof(listrec) * num));
  1379. X     if (! filelist) {
  1380. X      set_error(errno);
  1381. X      error("process_files");
  1382. X      return error_code;
  1383. X     }
  1384. X     
  1385. X     for (i = 0; i < num; i++) {
  1386. X      filelist[i].real_name = Malloc((unsigned) (strlen(files[i]) + 1));
  1387. X      if (! filelist[i].real_name) {
  1388. X           set_error(errno);
  1389. X           error("process_files");
  1390. X           return error_code;
  1391. X      }
  1392. X      (void) strcpy(filelist[i].real_name, files[i]);
  1393. X      filelist[i].user_name = Malloc((unsigned) (strlen(files[i]) + 1));
  1394. X      if (! filelist[i].user_name) {
  1395. X           set_error(errno);
  1396. X           error("process_files");
  1397. X           return error_code;
  1398. X      }
  1399. X       (void) convert_to_user_name(files[i], filelist[i].user_name);
  1400. X      free(files[i]);
  1401. X     }
  1402. X     free((char *) files);
  1403. X      
  1404. X     if (retval = sort_files(filelist, num)) {
  1405. X      error("sort_files");
  1406. X      return retval;
  1407. X     }
  1408. X     if (retval = unique(&filelist, &num)) {
  1409. X      error("unique");
  1410. X      return retval;
  1411. X     }
  1412. X     if (retval = initialize_tree()) {
  1413. X      error("initialize_tree");
  1414. X      return retval;
  1415. X     }
  1416. X      
  1417. X     for (i = 0; i < num; i++) {
  1418. X      if (retval = add_path_to_tree(filelist[i].real_name, ¬_needed)) {
  1419. X           error("add_path_to_tree");
  1420. X           return retval;
  1421. X      }
  1422. X      else {
  1423. X           free(filelist[i].real_name);
  1424. X           free(filelist[i].user_name);
  1425. X      }
  1426. X     }
  1427. X     free((char *) filelist);
  1428. X     return 0;
  1429. X}
  1430. X
  1431. X     
  1432. X
  1433. X
  1434. X
  1435. X
  1436. X
  1437. X     
  1438. Xdo_undelete(file_ent)
  1439. Xfilerec *file_ent;
  1440. X{
  1441. X     struct stat stat_buf;
  1442. X     char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
  1443. X     int retval;
  1444. X     
  1445. X     if (retval = get_leaf_path(file_ent, real_name)) {
  1446. X      if (! force)
  1447. X           fprintf(stderr, "%s: %s: %s\n", whoami, "get_leaf_path",
  1448. X               error_message(retval));
  1449. X      return retval;
  1450. X     }
  1451. X     
  1452. X     (void) convert_to_user_name(real_name, user_name);
  1453. X
  1454. X     if (interactive) {
  1455. X      if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
  1456. X           printf("%s: Undelete directory %s? ", whoami, user_name);
  1457. X      else
  1458. X           printf("%s: Undelete %s? ", whoami, user_name);
  1459. X      if (! yes()) {
  1460. X           set_status(UNDEL_NOT_UNDELETED);
  1461. X           return error_code;
  1462. X      }
  1463. X     }
  1464. X     if (! lstat(user_name, &stat_buf)) if (! force) {
  1465. X      printf("%s: An undeleted %s already exists.\n", whoami, user_name);
  1466. X      printf("Do you wish to continue with the undelete and overwrite that version? ");
  1467. X      if (! yes()) {
  1468. X           set_status(UNDEL_NOT_UNDELETED);
  1469. X           return error_code;
  1470. X      }
  1471. X      if (! noop) if (retval = unlink_completely(user_name)) {
  1472. X           error(user_name);
  1473. X           return retval;
  1474. X      }
  1475. X     }
  1476. X     if (noop) {
  1477. X      printf("%s: %s would be undeleted\n", whoami, user_name);
  1478. X      return 0;
  1479. X     }
  1480. X
  1481. X     if (retval = do_file_rename(real_name, user_name)) {
  1482. X      error("do_file_rename");
  1483. X      return retval;
  1484. X     }
  1485. X     else {
  1486. X      if (verbose)
  1487. X           printf("%s: %s undeleted\n", whoami, user_name);
  1488. X      return 0;
  1489. X     }
  1490. X}
  1491. X
  1492. X
  1493. X
  1494. X
  1495. Xdo_file_rename(real_name, user_name)
  1496. Xchar *real_name, *user_name;
  1497. X{
  1498. X     char *ptr;
  1499. X     int retval;
  1500. X     char error_buf[MAXPATHLEN+MAXPATHLEN+14];
  1501. X     char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
  1502. X     char buf[MAXPATHLEN];
  1503. X
  1504. X     (void) strcpy(old_name, real_name);
  1505. X     (void) strcpy(new_name, real_name);
  1506. X
  1507. X     while (ptr = strrindex(new_name, ".#")) {
  1508. X      (void) convert_to_user_name(ptr, ptr);
  1509. X      (void) strcpy(ptr, firstpart(ptr, buf));
  1510. X      (void) strcpy(&old_name[ptr - new_name],
  1511. X            firstpart(&old_name[ptr - new_name], buf));
  1512. X      if (rename(old_name, new_name)) {
  1513. X           set_error(errno);
  1514. X           (void) sprintf(error_buf, "renaming %s to %s",
  1515. X                  old_name, new_name);
  1516. X           error(error_buf);
  1517. X           return error_code;
  1518. X      }
  1519. X      if (ptr > new_name) {
  1520. X           *--ptr = '\0';
  1521. X           old_name[ptr - new_name] = '\0';
  1522. X      }
  1523. X     }
  1524. X     if (retval = change_path(real_name, user_name)) {
  1525. X      error("change_path");
  1526. X      return retval;
  1527. X     }
  1528. X     
  1529. X     return 0;
  1530. X}
  1531. X
  1532. X
  1533. X
  1534. X
  1535. X
  1536. X
  1537. Xfilecmp(file1, file2)
  1538. Xlistrec *file1, *file2;
  1539. X{
  1540. X     return(strcmp(file1->user_name, file2->user_name));
  1541. X}
  1542. X
  1543. X     
  1544. X     
  1545. Xint sort_files(data, num_data)
  1546. Xlistrec *data;
  1547. Xint num_data;
  1548. X{
  1549. X     qsort((char *) data, num_data, sizeof(listrec), filecmp);
  1550. X
  1551. X     return 0;
  1552. X}
  1553. X
  1554. X
  1555. X
  1556. X
  1557. X
  1558. Xint unique(the_files, number)
  1559. Xlistrec **the_files;
  1560. Xint *number;
  1561. X{
  1562. X     int i, last;
  1563. X     int offset;
  1564. X     listrec *files;
  1565. X
  1566. X     files = *the_files;
  1567. X     for (last = 0, i = 1; i < *number; i++) {
  1568. X      if (! strcmp(files[last].user_name, files[i].user_name)) {
  1569. X           int better;
  1570. X
  1571. X           better = choose_better(files[last].real_name,
  1572. X                      files[i].real_name);
  1573. X           if (better == 1) { /* the first one is better */
  1574. X            free (files[i].real_name);
  1575. X            free (files[i].user_name);
  1576. X            files[i].real_name = (char *) NULL;
  1577. X           }
  1578. X           else {
  1579. X            free (files[last].real_name);
  1580. X            free (files[last].user_name);
  1581. X            files[last].real_name = (char *) NULL;
  1582. X            last = i;
  1583. X           }
  1584. X      }
  1585. X      else
  1586. X           last = i;
  1587. X     }
  1588. X     
  1589. X     for (offset = 0, i = 0; i + offset < *number; i++) {
  1590. X      if (! files[i].real_name)
  1591. X           offset++;
  1592. X      if (i + offset < *number)
  1593. X           files[i] = files[i + offset];
  1594. X     }
  1595. X     *number -= offset;
  1596. X     files = (listrec *) realloc((char *) files,
  1597. X                 (unsigned) (sizeof(listrec) * *number));
  1598. X     if (! files) {
  1599. X      set_error(errno);
  1600. X      error("realloc");
  1601. X      return errno;
  1602. X     }
  1603. X
  1604. X     *the_files = files;
  1605. X     return 0;
  1606. X}
  1607. X
  1608. X
  1609. X
  1610. X
  1611. Xchoose_better(str1, str2)
  1612. Xchar *str1, *str2;
  1613. X{
  1614. X     char *pos1, *pos2;
  1615. X     
  1616. X     pos1 = strindex(str1, ".#");
  1617. X     pos2 = strindex(str2, ".#");
  1618. X     while (pos1 && pos2) {
  1619. X      if (pos1 - str1 < pos2 - str2)
  1620. X           return(2);
  1621. X      else if (pos2 - str2 < pos1 - str1)
  1622. X           return(1);
  1623. X      pos1 = strindex(pos1 + 1, ".#");
  1624. X      pos2 = strindex(pos2 + 1, ".#");
  1625. X     }
  1626. X     if (! pos1)
  1627. X      return(1);
  1628. X     else
  1629. X      return(2);
  1630. X}
  1631. X
  1632. X
  1633. X
  1634. X
  1635. X     
  1636. Xunlink_completely(filename)
  1637. Xchar *filename;
  1638. X{
  1639. X     char buf[MAXPATHLEN];
  1640. X     struct stat stat_buf;
  1641. X     DIR *dirp;
  1642. X     struct direct *dp;
  1643. X     int retval;
  1644. X     int status = 0;
  1645. X     
  1646. X     if (lstat(filename, &stat_buf)) {
  1647. X      set_error(errno);
  1648. X      error(filename);
  1649. X      return error_code;
  1650. X     }
  1651. X
  1652. X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  1653. X      dirp = Opendir(filename);
  1654. X      if (! dirp) {
  1655. X           set_error(errno);
  1656. X           error(filename);
  1657. X           return error_code;
  1658. X      }
  1659. X           
  1660. X      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  1661. X           if (is_dotfile(dp->d_name))
  1662. X            continue;
  1663. X           (void) strcpy(buf, append(filename, dp->d_name));
  1664. X           if (retval = unlink_completely(buf)) {
  1665. X            error(buf);
  1666. X            status = retval;
  1667. X           }
  1668. X      }
  1669. X      closedir(dirp);
  1670. X      if (retval = rmdir(filename)) {
  1671. X           set_error(errno);
  1672. X           error(filename);
  1673. X           return error_code;
  1674. X      }
  1675. X     }
  1676. X     else if (retval = unlink(filename)) {
  1677. X      set_error(errno);
  1678. X      error(filename);
  1679. X      return error_code;
  1680. X     }
  1681. X
  1682. X     return status;
  1683. X}
  1684. X
  1685. X
  1686. X
  1687. X
  1688. Xint get_the_files(name, num_found, found)
  1689. Xchar *name;
  1690. Xint *num_found;
  1691. Xchar ***found;
  1692. X{
  1693. X     int retval;
  1694. X     int options;
  1695. X     
  1696. X     options = FIND_DELETED;
  1697. X     if (recursive)
  1698. X      options |= RECURS_DELETED;
  1699. X     if (! directoriesonly)
  1700. X      options |= FIND_CONTENTS;
  1701. X
  1702. X     retval = find_matches(name, num_found, found, options);
  1703. X     if (retval) {
  1704. X      error("find_matches");
  1705. X      return retval;
  1706. X     }
  1707. X
  1708. X     return 0;
  1709. X}
  1710. END_OF_FILE
  1711. if test 12715 -ne `wc -c <'undelete.c'`; then
  1712.     echo shar: \"'undelete.c'\" unpacked with wrong size!
  1713. fi
  1714. # end of 'undelete.c'
  1715. fi
  1716. if test -f 'util.c' -a "${1}" != "-c" ; then 
  1717.   echo shar: Will not clobber existing file \"'util.c'\"
  1718. else
  1719. echo shar: Extracting \"'util.c'\" \(8062 characters\)
  1720. sed "s/^X//" >'util.c' <<'END_OF_FILE'
  1721. X/*
  1722. X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/util.c,v $
  1723. X * $Author: jik $
  1724. X *
  1725. X * This program is a replacement for rm.  Instead of actually deleting
  1726. X * files, it marks them for deletion by prefixing them with a ".#"
  1727. X * prefix.
  1728. X *
  1729. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  1730. X * For copying and distribution information, see the file "mit-copyright.h."
  1731. X */
  1732. X
  1733. X#if (!defined(lint) && !defined(SABER))
  1734. X     static char rcsid_util_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/util.c,v 1.21 91/02/20 17:28:11 jik Exp $";
  1735. X#endif
  1736. X
  1737. X#include <stdio.h>
  1738. X#include <sys/param.h>
  1739. X#include <sys/types.h>
  1740. X#ifdef SYSV /* SYSV doesn't define uid_t */
  1741. Xtypedef unsigned short uid_t;
  1742. X#endif
  1743. X#include <sys/dir.h>
  1744. X#ifdef SYSV
  1745. X#include <string.h>
  1746. X#define index strchr
  1747. X#define rindex strrchr
  1748. X#else
  1749. X#include <strings.h>
  1750. X#endif /* SYSV */
  1751. X#include <pwd.h>
  1752. X#include <errno.h>
  1753. X#ifdef AFS_MOUNTPOINTS
  1754. X#include <sys/ioctl.h>
  1755. X#include <afs/param.h>
  1756. X#include <afs/vice.h>
  1757. X#include <afs/venus.h>
  1758. X#endif
  1759. X#include "delete_errs.h"
  1760. X#include "util.h"
  1761. X#include "directories.h"
  1762. X#include "mit-copyright.h"
  1763. X#include "errors.h"
  1764. X
  1765. Xextern char *getenv();
  1766. Xextern uid_t getuid();
  1767. Xextern int errno;
  1768. X
  1769. Xchar *convert_to_user_name(real_name, user_name)
  1770. Xchar real_name[];
  1771. Xchar user_name[];  /* RETURN */
  1772. X{
  1773. X     char *ptr, *q;
  1774. X     
  1775. X     (void) strcpy(user_name, real_name);
  1776. X     while (ptr = strrindex(user_name, ".#")) {
  1777. X      for (q = ptr; *(q + 2); q++)
  1778. X           *q = *(q + 2);
  1779. X      *q = '\0';
  1780. X     }
  1781. X     return (user_name);
  1782. X}
  1783. X
  1784. X     
  1785. X
  1786. X
  1787. X
  1788. Xchar *strindex(str, sub_str)
  1789. Xchar *str, *sub_str;
  1790. X{
  1791. X     char *ptr = str;
  1792. X     while (ptr = index(ptr, *sub_str)) {
  1793. X      if (! strncmp(ptr, sub_str, strlen(sub_str)))
  1794. X           return(ptr);
  1795. X      ptr++;
  1796. X     }
  1797. X     return ((char *) NULL);
  1798. X}
  1799. X
  1800. X
  1801. X
  1802. Xchar *strrindex(str, sub_str)
  1803. Xchar *str, *sub_str;
  1804. X{
  1805. X     char *ptr;
  1806. X
  1807. X     if (strlen(str))
  1808. X      ptr = &str[strlen(str) - 1];
  1809. X     else
  1810. X      return((char *) NULL);
  1811. X     while ((*ptr != *sub_str) && (ptr != str)) ptr--;
  1812. X     while (ptr != str) {
  1813. X      if (! strncmp(ptr, sub_str, strlen(sub_str)))
  1814. X           return(ptr);
  1815. X      ptr--;
  1816. X      while ((*ptr != *sub_str) && (ptr != str)) ptr--;
  1817. X     }
  1818. X     if (! strncmp(ptr, sub_str, strlen(sub_str)))
  1819. X      return(str);
  1820. X     else
  1821. X      return ((char *) NULL);
  1822. X}
  1823. X     
  1824. X     
  1825. X/*
  1826. X * NOTE: Append uses a static array, so its return value must be
  1827. X * copied immediately.
  1828. X */
  1829. Xchar *append(filepath, filename)
  1830. Xchar *filepath, *filename;
  1831. X{
  1832. X     static char buf[MAXPATHLEN];
  1833. X
  1834. X     (void) strcpy(buf, filepath);
  1835. X     if ((! *filename) || (! *filepath)) {
  1836. X      (void) strcpy(buf, filename);
  1837. X      return(buf);
  1838. X     }
  1839. X     if (buf[strlen(buf) - 1] == '/')
  1840. X      buf[strlen(buf) - 1] = '\0';
  1841. X     if (strlen(buf) + strlen(filename) + 2 > MAXPATHLEN) {
  1842. X      set_error(ENAMETOOLONG);
  1843. X      strncat(buf, "/", MAXPATHLEN - strlen(buf) - 1);
  1844. X      strncat(buf, filename, MAXPATHLEN - strlen(buf) - 1);
  1845. X      error(buf);
  1846. X       *buf = '\0';
  1847. X      return buf;
  1848. X     }
  1849. X     (void) strcat(buf, "/");
  1850. X     (void) strcat(buf, filename);
  1851. X     return buf;
  1852. X}
  1853. X
  1854. X
  1855. X
  1856. X
  1857. Xyes() {
  1858. X     char buf[BUFSIZ];
  1859. X     char *val;
  1860. X     
  1861. X     val = fgets(buf, BUFSIZ, stdin);
  1862. X     if (! val) {
  1863. X      printf("\n");
  1864. X      exit(1);
  1865. X     }
  1866. X     if (! index(buf, '\n')) do
  1867. X      (void) fgets(buf + 1, BUFSIZ - 1, stdin);
  1868. X     while (! index(buf + 1, '\n'));
  1869. X     return(*buf == 'y');
  1870. X}
  1871. X
  1872. X
  1873. X
  1874. X
  1875. Xchar *lastpart(filename)
  1876. Xchar *filename;
  1877. X{
  1878. X     char *part;
  1879. X
  1880. X     part = rindex(filename, '/');
  1881. X
  1882. X     if (! part)
  1883. X      part = filename;
  1884. X     else if (part == filename)
  1885. X      part++;
  1886. X     else if (part - filename + 1 == strlen(filename)) {
  1887. X      part = rindex(--part, '/');
  1888. X      if (! part)
  1889. X           part = filename;
  1890. X      else
  1891. X           part++;
  1892. X     }
  1893. X     else
  1894. X      part++;
  1895. X
  1896. X     return(part);
  1897. X}
  1898. X
  1899. X
  1900. X
  1901. X
  1902. Xchar *firstpart(filename, rest)
  1903. Xchar *filename;
  1904. Xchar *rest; /* RETURN */
  1905. X{
  1906. X     char *part;
  1907. X     static char buf[MAXPATHLEN];
  1908. X
  1909. X     (void) strcpy(buf, filename);
  1910. X     part = index(buf, '/');
  1911. X     if (! part) {
  1912. X      *rest = '\0';
  1913. X      return(buf);
  1914. X     }
  1915. X     (void) strcpy(rest, part + 1);
  1916. X     *part = '\0';
  1917. X     return(buf);
  1918. X}
  1919. X
  1920. X
  1921. X
  1922. X
  1923. X
  1924. Xget_home(buf)
  1925. Xchar *buf;
  1926. X{
  1927. X     char *user;
  1928. X     struct passwd *psw;
  1929. X     
  1930. X     (void) strcpy(buf, getenv("HOME"));
  1931. X     
  1932. X     if (*buf)
  1933. X      return(0);
  1934. X
  1935. X     user = getenv("USER");
  1936. X     psw = getpwnam(user);
  1937. X
  1938. X     if (psw) {
  1939. X      (void) strcpy(buf, psw->pw_dir);
  1940. X      return(0);
  1941. X     }
  1942. X     
  1943. X     psw = getpwuid((int) getuid());
  1944. X
  1945. X     if (psw) {
  1946. X      (void) strcpy(buf, psw->pw_dir);
  1947. X      return(0);
  1948. X     }
  1949. X
  1950. X     set_error(NO_HOME_DIR);
  1951. X     error("get_home");
  1952. X     return error_code;
  1953. X}
  1954. X
  1955. X
  1956. X
  1957. X
  1958. Xtimed_out(file_ent, current_time, min_days)
  1959. Xfilerec *file_ent;
  1960. Xtime_t current_time, min_days;
  1961. X{
  1962. X     if ((current_time - file_ent->specs.st_ctime) / 86400 >= min_days)
  1963. X      return(1);
  1964. X     else
  1965. X      return(0);
  1966. X}
  1967. X
  1968. X
  1969. X
  1970. Xint directory_exists(dirname)
  1971. Xchar *dirname;
  1972. X{
  1973. X     struct stat stat_buf;
  1974. X
  1975. X     if (stat(dirname, &stat_buf))
  1976. X      return(0);
  1977. X     else if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)
  1978. X      return(1);
  1979. X     else
  1980. X      return(0);
  1981. X}
  1982. X
  1983. X
  1984. X
  1985. Xis_link(name, oldbuf)
  1986. Xchar *name;
  1987. Xstruct stat *oldbuf;
  1988. X{
  1989. X#ifdef S_IFLNK
  1990. X     struct stat statbuf;
  1991. X
  1992. X     if (oldbuf)
  1993. X      statbuf = *oldbuf;
  1994. X     else if (lstat(name, &statbuf) < 0) {
  1995. X      set_error(errno);
  1996. X      error("is_link");
  1997. X      return(0);
  1998. X     }
  1999. X
  2000. X     if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  2001. X      return 1;
  2002. X     else
  2003. X#endif
  2004. X      return 0;
  2005. X}
  2006. X
  2007. X
  2008. X
  2009. X/*
  2010. X * This is one of the few procedures that is allowed to break the
  2011. X * rule of always returning an error value if an error occurs.  That's
  2012. X * because it's stupid to expect a boolean function to do that, and
  2013. X * because defaulting to not being a mountpoint if there is an error
  2014. X * is a reasonable thing to do.
  2015. X */
  2016. X/*
  2017. X * The second parameter is optional -- if it is non-NULL, it is
  2018. X * presumed to be a stat structure for the file being passed in.
  2019. X */
  2020. Xint is_mountpoint(name, oldbuf)
  2021. Xchar *name;
  2022. Xstruct stat *oldbuf;
  2023. X{
  2024. X     struct stat statbuf;
  2025. X     dev_t device;
  2026. X     char buf[MAXPATHLEN];
  2027. X#ifdef AFS_MOUNTPOINTS
  2028. X     struct ViceIoctl blob;
  2029. X     char retbuf[MAXPATHLEN];
  2030. X     int retval;
  2031. X     char *shortname;
  2032. X#endif
  2033. X
  2034. X     /* First way to check for a mount point -- if the device number */
  2035. X     /* of name is different from the device number of name/..       */
  2036. X     if (oldbuf)
  2037. X      statbuf = *oldbuf;
  2038. X     else if (lstat(name, &statbuf) < 0) {
  2039. X      set_error(errno);
  2040. X      error(name);
  2041. X      return 0;
  2042. X     }
  2043. X
  2044. X     device = statbuf.st_dev;
  2045. X
  2046. X     if (strlen(name) + 4 /* length of "/.." + a NULL */ > MAXPATHLEN) {
  2047. X      set_error(ENAMETOOLONG);
  2048. X      error(name);
  2049. X      return 0;
  2050. X     }
  2051. X
  2052. X     strcpy(buf, name);
  2053. X     strcat(buf, "/..");
  2054. X     if (lstat(buf, &statbuf) < 0) {
  2055. X      set_error(errno);
  2056. X      error(name);
  2057. X      return 0;
  2058. X     }
  2059. X
  2060. X     if (statbuf.st_dev != device)
  2061. X      return 1;
  2062. X
  2063. X#ifdef AFS_MOUNTPOINTS
  2064. X     /* Check for AFS mountpoint using the AFS pioctl call. */
  2065. X     if ((shortname = lastpart(name)) == name) {
  2066. X      strcpy(buf, ".");
  2067. X      blob.in = name;
  2068. X      blob.in_size = strlen(name) + 1;
  2069. X      blob.out = retbuf;
  2070. X      blob.out_size = MAXPATHLEN;
  2071. X      bzero(retbuf, MAXPATHLEN);
  2072. X     }
  2073. X     else {
  2074. X      strncpy(buf, name, shortname - name - 1);
  2075. X      buf[shortname - name - 1] = '\0';
  2076. X      if (*buf == '\0')
  2077. X           strcpy(buf, "/");
  2078. X      blob.in = shortname;
  2079. X      blob.in_size = strlen(shortname) + 1;
  2080. X      blob.out = retbuf;
  2081. X      blob.out_size = MAXPATHLEN;
  2082. X      bzero(retbuf, MAXPATHLEN);
  2083. X     }
  2084. X
  2085. X     retval = pioctl(buf, VIOC_AFS_STAT_MT_PT, &blob, 0);
  2086. X
  2087. X     if (retval == 0) {
  2088. X#ifdef DEBUG
  2089. X      printf("%s is an AFS mountpoint, is_mountpoint returning true.\n",
  2090. X         name);
  2091. X#endif
  2092. X      return 1;
  2093. X     }
  2094. X     else {
  2095. X      if (errno != EINVAL) {
  2096. X           set_error(errno);
  2097. X           error(name);
  2098. X      }
  2099. X     }
  2100. X#endif /* AFS_MOUNTPOINTS */
  2101. X
  2102. X     return 0;
  2103. X}
  2104. X
  2105. X#ifdef MALLOC_DEBUG
  2106. Xchar *Malloc(size)
  2107. Xunsigned size;
  2108. X{
  2109. X     extern char *malloc();
  2110. X
  2111. X     static int count = 0;
  2112. X     char buf[10];
  2113. X     
  2114. X     count++;
  2115. X
  2116. X     fprintf(stderr, "This is call number %d to Malloc, for %u bytes.\n",
  2117. X         count, size);
  2118. X     fprintf(stdout, "Shall I return NULL for this malloc? ");
  2119. X     fgets(buf, 10, stdin);
  2120. X     if ((*buf == 'y') || (*buf == 'Y')) {
  2121. X      errno = ENOMEM;
  2122. X      return ((char *) NULL);
  2123. X     }
  2124. X     else
  2125. X      return (malloc(size));
  2126. X}
  2127. X#endif
  2128. X
  2129. X      
  2130. END_OF_FILE
  2131. if test 8062 -ne `wc -c <'util.c'`; then
  2132.     echo shar: \"'util.c'\" unpacked with wrong size!
  2133. fi
  2134. # end of 'util.c'
  2135. fi
  2136. echo shar: End of archive 2 \(of 4\).
  2137. cp /dev/null ark2isdone
  2138. MISSING=""
  2139. for I in 1 2 3 4 ; do
  2140.     if test ! -f ark${I}isdone ; then
  2141.     MISSING="${MISSING} ${I}"
  2142.     fi
  2143. done
  2144. if test "${MISSING}" = "" ; then
  2145.     echo You have unpacked all 4 archives.
  2146.     rm -f ark[1-9]isdone
  2147. else
  2148.     echo You still need to unpack the following archives:
  2149.     echo "        " ${MISSING}
  2150. fi
  2151. ##  End of shell archive.
  2152. exit 0
  2153.  
  2154. exit 0 # Just in case...
  2155. -- 
  2156. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2157. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2158. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2159. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2160.